package com.kurt.service.impl;

import com.kurt.dto.create.VehicleDriverCreateRequest;
import com.kurt.dto.create.VehicleDriverDTO;
import com.kurt.dto.query.VehicleDriverQueryRequest;
import com.kurt.entity.SysDriver;
import com.kurt.entity.SysVehicle;
import com.kurt.entity.SysVehicleDriver;
import com.kurt.repository.SysDriverRepository;
import com.kurt.repository.SysVehicleDriverRepository;
import com.kurt.repository.SysVehicleRepository;
import com.kurt.service.DataPermissionService;
import com.kurt.service.VehicleDriverService;
import com.kurt.util.DataPermissionUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;

/**
 * 车辆驾驶员关联服务实现类
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class VehicleDriverServiceImpl extends BaseServiceImpl<SysVehicleDriver, Long> implements VehicleDriverService {

    private final SysVehicleDriverRepository vehicleDriverRepository;
    private final SysVehicleRepository vehicleRepository;
    private final SysDriverRepository driverRepository;
    private final DataPermissionService dataPermissionService;
    private final DataPermissionUtil dataPermissionUtil;

    @Override
    protected SysVehicleDriverRepository getRepository() {
        return vehicleDriverRepository;
    }

    @Override
    protected SysVehicleDriverRepository getSpecificationExecutor() {
        return vehicleDriverRepository;
    }

    @Override
    @Transactional
    public VehicleDriverDTO bindVehicleDriver(VehicleDriverCreateRequest createRequest) {
        log.info("绑定车辆和驾驶员: vehicleId={}, driverId={}", createRequest.getVehicleId(), createRequest.getDriverId());

        // 检查车辆是否存在
        Optional<SysVehicle> vehicleOpt = vehicleRepository.findById(createRequest.getVehicleId());
        if (vehicleOpt.isEmpty()) {
            throw new RuntimeException("车辆不存在");
        }

        // 检查驾驶员是否存在
        Optional<SysDriver> driverOpt = driverRepository.findById(createRequest.getDriverId());
        if (driverOpt.isEmpty()) {
            throw new RuntimeException("驾驶员不存在");
        }

        // 检查是否已绑定
        if (vehicleDriverRepository.existsByVehicleIdAndDriverId(createRequest.getVehicleId(), createRequest.getDriverId())) {
            throw new RuntimeException("车辆和驾驶员已绑定");
        }

        // 创建绑定记录
        SysVehicleDriver vehicleDriver = new SysVehicleDriver();
        vehicleDriver.setVehicleId(createRequest.getVehicleId());
        vehicleDriver.setDriverId(createRequest.getDriverId());
        vehicleDriver.setCreateTime(LocalDateTime.now());
        vehicleDriver.setCreateUserId(com.kurt.util.UserContext.getUserId());

        // 保存绑定记录
        vehicleDriver = vehicleDriverRepository.save(vehicleDriver);

        // 自动给创建人赋予该绑定记录的数据权限
        Long currentUserId = com.kurt.util.UserContext.getUserId();
        if (currentUserId != null) {
            try {
                dataPermissionService.createDataPermission(
                        new com.kurt.dto.create.DataPermissionCreateRequest(currentUserId, "vehicle_driver", vehicleDriver.getId())
                );
                log.info("自动为创建人{}赋予车辆驾驶员绑定{}的数据权限", currentUserId, vehicleDriver.getId());
            } catch (Exception e) {
                log.error("自动赋予车辆驾驶员绑定数据权限失败: userId={}, vehicleDriverId={}", currentUserId, vehicleDriver.getId(), e);
            }
        }

        log.info("车辆和驾驶员绑定成功: vehicleId={}, driverId={}", createRequest.getVehicleId(), createRequest.getDriverId());
        return convertToVehicleDriverDTO(vehicleDriver);
    }

    @Override
    @Transactional
    public boolean unbindVehicleDriver(Long vehicleId, Long driverId) {
        log.info("解绑车辆和驾驶员: vehicleId={}, driverId={}", vehicleId, driverId);

        // 检查绑定是否存在
        if (!vehicleDriverRepository.existsByVehicleIdAndDriverId(vehicleId, driverId)) {
            throw new RuntimeException("车辆和驾驶员未绑定");
        }

        // 删除绑定记录
        vehicleDriverRepository.deleteByVehicleIdAndDriverId(vehicleId, driverId);

        log.info("车辆和驾驶员解绑成功: vehicleId={}, driverId={}", vehicleId, driverId);
        return true;
    }

    @Override
    @Transactional
    public boolean bindVehicleDrivers(Long vehicleId, List<Long> driverIds, Long userId) {
        log.info("批量绑定车辆和驾驶员: vehicleId={}, driverIds={}", vehicleId, driverIds);

        // 检查车辆是否存在
        if (!vehicleRepository.existsById(vehicleId)) {
            throw new RuntimeException("车辆不存在");
        }

        int successCount = 0;
        for (Long driverId : driverIds) {
            try {
                VehicleDriverCreateRequest createRequest = new VehicleDriverCreateRequest();
                createRequest.setVehicleId(vehicleId);
                createRequest.setDriverId(driverId);
                createRequest.setCreateUserId(userId);
                bindVehicleDriver(createRequest);
                successCount++;
            } catch (Exception e) {
                log.warn("绑定车辆{}和驾驶员{}失败: {}", vehicleId, driverId, e.getMessage());
            }
        }

        log.info("批量绑定完成: 成功{}个，失败{}个", successCount, driverIds.size() - successCount);
        return successCount > 0;
    }

    @Override
    @Transactional
    public boolean unbindVehicleDrivers(Long vehicleId, List<Long> driverIds) {
        log.info("批量解绑车辆和驾驶员: vehicleId={}, driverIds={}", vehicleId, driverIds);

        int successCount = 0;
        for (Long driverId : driverIds) {
            try {
                unbindVehicleDriver(vehicleId, driverId);
                successCount++;
            } catch (Exception e) {
                log.warn("解绑车辆{}和驾驶员{}失败: {}", vehicleId, driverId, e.getMessage());
            }
        }

        log.info("批量解绑完成: 成功{}个，失败{}个", successCount, driverIds.size() - successCount);
        return successCount > 0;
    }

    @Override
    public Page<VehicleDriverDTO> getVehicleDriverPage(VehicleDriverQueryRequest queryRequest) {
        // 构建分页参数
        Sort sort = Sort.by(Sort.Direction.fromString(queryRequest.getOrderDirection()), queryRequest.getOrderBy());
        Pageable pageable = PageRequest.of(queryRequest.getPageNum() - 1, queryRequest.getPageSize(), sort);

        // 构建查询条件
        Specification<SysVehicleDriver> spec = buildVehicleDriverSpecification(queryRequest);

        // 执行分页查询
        Page<SysVehicleDriver> vehicleDriverPage = vehicleDriverRepository.findAll(spec, pageable);

        // 转换为DTO
        return vehicleDriverPage.map(this::convertToVehicleDriverDTO);
    }

    @Override
    public List<VehicleDriverDTO> getVehicleDriverList(VehicleDriverQueryRequest queryRequest) {
        // 构建查询条件
        Specification<SysVehicleDriver> spec = buildVehicleDriverSpecification(queryRequest);

        // 执行查询
        List<SysVehicleDriver> vehicleDrivers = vehicleDriverRepository.findAll(spec);

        // 转换为DTO
        return vehicleDrivers.stream().map(this::convertToVehicleDriverDTO).collect(Collectors.toList());
    }

    @Override
    public List<VehicleDriverDTO> getDriversByVehicleId(Long vehicleId) {
        // 数据权限过滤
        Long currentUserId = com.kurt.util.UserContext.getUserId();
        if (currentUserId == null) {
            log.warn("用户未登录，无法获取车辆驾驶员绑定数据");
            return new ArrayList<>();
        }

        List<Long> authorizedVehicleDriverIds = dataPermissionUtil.getAuthorizedResourceIds(currentUserId, "vehicle_driver");
        if (authorizedVehicleDriverIds.isEmpty() || authorizedVehicleDriverIds.contains(-1L)) {
            log.warn("用户{}没有车辆驾驶员绑定数据权限", currentUserId);
            return new ArrayList<>();
        }

        List<SysVehicleDriver> vehicleDrivers = vehicleDriverRepository.findByVehicleId(vehicleId);
        List<SysVehicleDriver> filteredVehicleDrivers = vehicleDrivers.stream()
                .filter(vd -> authorizedVehicleDriverIds.contains(vd.getId()))
                .collect(Collectors.toList());

        return filteredVehicleDrivers.stream().map(this::convertToVehicleDriverDTO).collect(Collectors.toList());
    }

    @Override
    public List<VehicleDriverDTO> getVehiclesByDriverId(Long driverId) {
        // 数据权限过滤
        Long currentUserId = com.kurt.util.UserContext.getUserId();
        if (currentUserId == null) {
            log.warn("用户未登录，无法获取车辆驾驶员绑定数据");
            return new ArrayList<>();
        }

        List<Long> authorizedVehicleDriverIds = dataPermissionUtil.getAuthorizedResourceIds(currentUserId, "vehicle_driver");
        if (authorizedVehicleDriverIds.isEmpty() || authorizedVehicleDriverIds.contains(-1L)) {
            log.warn("用户{}没有车辆驾驶员绑定数据权限", currentUserId);
            return new ArrayList<>();
        }

        List<SysVehicleDriver> vehicleDrivers = vehicleDriverRepository.findByDriverId(driverId);
        List<SysVehicleDriver> filteredVehicleDrivers = vehicleDrivers.stream()
                .filter(vd -> authorizedVehicleDriverIds.contains(vd.getId()))
                .collect(Collectors.toList());

        return filteredVehicleDrivers.stream().map(this::convertToVehicleDriverDTO).collect(Collectors.toList());
    }

    @Override
    public boolean isVehicleDriverBound(Long vehicleId, Long driverId) {
        return vehicleDriverRepository.existsByVehicleIdAndDriverId(vehicleId, driverId);
    }

    /**
     * 构建车辆驾驶员关联查询条件
     */
    private Specification<SysVehicleDriver> buildVehicleDriverSpecification(VehicleDriverQueryRequest queryRequest) {
        return (root, query, cb) -> {
            List<jakarta.persistence.criteria.Predicate> predicates = new ArrayList<>();

            // 数据权限过滤
            Long currentUserId = queryRequest.getLoginUserId();
            if (currentUserId != null) {
                List<Long> authorizedVehicleDriverIds = dataPermissionUtil.getAuthorizedResourceIds(currentUserId, "vehicle_driver");
                predicates.add(root.get("id").in(authorizedVehicleDriverIds));
            }

            // 车辆ID查询
            if (queryRequest.getVehicleId() != null) {
                predicates.add(cb.equal(root.get("vehicleId"), queryRequest.getVehicleId()));
            }

            // 驾驶员ID查询
            if (queryRequest.getDriverId() != null) {
                predicates.add(cb.equal(root.get("driverId"), queryRequest.getDriverId()));
            }

            // 创建用户ID查询
            if (queryRequest.getCreateUserId() != null) {
                predicates.add(cb.equal(root.get("createUserId"), queryRequest.getCreateUserId()));
            }

            // 创建时间范围查询
            if (StringUtils.hasText(queryRequest.getCreateTimeStart())) {
                predicates.add(cb.greaterThanOrEqualTo(root.get("createTime"),
                        LocalDateTime.parse(queryRequest.getCreateTimeStart())));
            }
            if (StringUtils.hasText(queryRequest.getCreateTimeEnd())) {
                predicates.add(cb.lessThanOrEqualTo(root.get("createTime"),
                        LocalDateTime.parse(queryRequest.getCreateTimeEnd())));
            }

            return cb.and(predicates.toArray(new jakarta.persistence.criteria.Predicate[0]));
        };
    }

    /**
     * 转换车辆驾驶员关联实体为DTO
     */
    private VehicleDriverDTO convertToVehicleDriverDTO(SysVehicleDriver vehicleDriver) {
        VehicleDriverDTO dto = new VehicleDriverDTO();
        BeanUtils.copyProperties(vehicleDriver, dto);

        // 获取车辆信息
        Optional<SysVehicle> vehicleOpt = vehicleRepository.findById(vehicleDriver.getVehicleId());
        if (vehicleOpt.isPresent()) {
            dto.setVehicleLicensePlate(vehicleOpt.get().getLicensePlate());
        }

        // 获取驾驶员信息
        Optional<SysDriver> driverOpt = driverRepository.findById(vehicleDriver.getDriverId());
        if (driverOpt.isPresent()) {
            dto.setDriverName(driverOpt.get().getName());
        }

        return dto;
    }
}
